"""对外暴露的简化接口

提供：
- parse_pdf_to_shared / parse_pdf_to_shared_async：接收PDF路径，运行现有流程，返回精简shared
- rollback_shared：基于修改记录回滚，更新精简shared

精简shared仅包含：
- final_output: dict       最终JSON对象（统一为字典对象）
- modification_log: list   修改记录（最多3条）
- error_log: list          错误信息列表
"""

from typing import Any, Dict

from .flow import create_proofmapper_flow
from .utils.json_modifier import json_modifier
from .nodes import ApplyUserInputNode


def _ensure_dict_final_output(final_output: Any) -> Dict[str, Any]:
    """将final_output规范为dict（统一为字典对象）。"""
    return final_output if isinstance(final_output, dict) else {}


async def parse_pdf_to_shared_async(pdf_path: str, output_path: str = "output.json") -> Dict[str, Any]:
    """异步解析PDF为最终JSON，并返回精简shared。

    注意：内部复用现有异步流程，会将结果同时写入 output_path（由流程中的 SaveJSONNode 完成）。

    Args:
        pdf_path: PDF文件路径
        output_path: 输出JSON文件路径（流程会写入此文件）

    Returns:
        精简shared字典，包含 final_output, modification_log, error_log
    """
    shared: Dict[str, Any] = {
        # 完整流程需要的关键输入
        "pdf_path": pdf_path,
        "output_path": output_path,
        # 流程中会填充的字段
        "pdf_text": "",
        "text_chunks": [],
        "chunk_checkpoints": {},
        "checkpoints": [],
        "materials": [],
        # 结果及交互相关
        "final_output": {},
        "modification_log": [],
        "enable_interactive": False,
        # 对外接口新增的错误日志
        "error_log": [],
    }

    try:
        flow = create_proofmapper_flow()
        await flow.run_async(shared)
    except Exception as e:
        # 记录错误并继续返回精简shared
        shared.setdefault("error_log", []).append(f"parse error: {str(e)}")

    # 规范结果，仅保留精简shared
    result: Dict[str, Any] = {
        "final_output": shared.get("final_output", {}),
        "modification_log": shared.get("modification_log", []),
        "error_log": shared.get("error_log", []),
    }
    return result



def rollback_shared(simplified_shared: Dict[str, Any]) -> Dict[str, Any]:
    """基于修改记录执行回滚，并返回更新后的精简shared。

    输入应为精简shared（仅包含 final_output, modification_log, error_log）。
    该函数会：
    - 使用 json_modifier.rollback_last_modification 回滚最近一次修改
    - 成功时更新 final_output
    - 失败或无可回滚记录时，写入 error_log
    """
    final_output = simplified_shared.get("final_output", {})
    modification_log = simplified_shared.get("modification_log", [])
    error_log = simplified_shared.get("error_log", [])

    try:
        current_json = _ensure_dict_final_output(final_output)
        # json_modifier 需要完整的记录以恢复
        rolled_back = json_modifier.rollback_last_modification(modification_log)
        if rolled_back is None:
            error_log.append("no modification to rollback")
            return {
                "final_output": current_json,
                "modification_log": modification_log,
                "error_log": error_log,
            }

        # 回滚成功：更新final_output
        return {
            "final_output": rolled_back,
            "modification_log": modification_log,
            "error_log": error_log,
        }

    except Exception as e:
        error_log.append(f"rollback error: {str(e)}")
        return {
            "final_output": simplified_shared.get("final_output", {}),
            "modification_log": modification_log,
            "error_log": error_log,
        }


async def apply_user_input_async(user_input: str, simplified_shared: Dict[str, Any]) -> Dict[str, Any]:
    """根据用户输入对列表进行修改（异步）。复用 ApplyUserInputNode。"""
    # 将 user_input 填入 shared，并确保必要键存在
    simplified_shared["user_input"] = user_input
    simplified_shared.setdefault("modification_log", [])
    simplified_shared.setdefault("error_log", [])

    # 运行节点生命周期（不依赖完整 Flow）
    node = ApplyUserInputNode()
    prep_res = await node.prep_async(simplified_shared)
    exec_res = await node.exec_async(prep_res)
    await node.post_async(simplified_shared, prep_res, exec_res)

    # 返回精简 shared
    return {
        "final_output": simplified_shared.get("final_output", {}),
        "modification_log": simplified_shared.get("modification_log", []),
        "error_log": simplified_shared.get("error_log", []),
        "ok": exec_res.get("ok", False),
        "message": exec_res.get("message", ""),
    }

